package com.yumeng.framework.persistence.mybatis.injector;

import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils;
import com.yumeng.config.helper.PropHelper;
import com.yumeng.config.properties.YumengMybatisPlusProperties;
import com.yumeng.framework.persistence.mybatis.data.MybatisPlusExtConstants;

import java.util.Objects;

import static java.util.stream.Collectors.joining;

/**
 * 抽象的注入方法类（自定义）
 *
 * @author wxd
 * @date 2022/8/22 16:34
 */
public abstract class MyAbstractMethod extends AbstractMethod {

    private static YumengMybatisPlusProperties mybatisPlusProperties;
    protected static YumengMybatisPlusProperties getMybatisPlusProperties() {
        if (mybatisPlusProperties == null) {
            mybatisPlusProperties = PropHelper.getMybatisPlusProperties();
        }
        return mybatisPlusProperties;
    }

    protected MyAbstractMethod(String methodName) {
        super(methodName);
    }

    //region 逻辑删除

    /**
     * 判断是否存在逻辑删除字段
     * @param table
     * @return
     */
    protected boolean myHasLogicDelete(TableInfo table){
        return table.getFieldList().stream().anyMatch(p->p.getColumn().equals(getMybatisPlusProperties().getLogicDeleteField()));
    }

    /**
     * 更新 set 语句（逻辑删除）
     * @param table
     * @return
     */
    protected String mySqlLogicSet(TableInfo table, String prefix) {
        return "SET " + myGetLogicDeleteSql(false, false, prefix);
    }

    /**
     * 获取逻辑删除字段的 sql 脚本
     * @param startWithAnd
     * @param isWhere
     * @return
     */
    protected String myGetLogicDeleteSql(boolean startWithAnd, boolean isWhere, String prefix) {
        String logicDeleteSql = myFormatLogicDeleteSql(isWhere, prefix);
        if (startWithAnd) {
            logicDeleteSql = " AND " + logicDeleteSql;
        }
        return logicDeleteSql;
    }

    private String myFormatLogicDeleteSql(boolean isWhere, String prefix) {
        final String value = isWhere ? getMybatisPlusProperties().getUnLogicDeleteVal() : getMybatisPlusProperties().getLogicDeleteVal();
        if (isWhere) {
            return getMybatisPlusProperties().getLogicDeleteField() + EQUALS + String.format("%s", value);
        }
        prefix = StringUtils.isNotBlank(prefix) ? prefix : "";
        //del_flag = 1, deler = #{deler}, del_time = #{delTime}
        return String.format("%s = %s, %s = #{%s}, %s = #{%s}", getMybatisPlusProperties().getLogicDeleteField(), value,
                getMybatisPlusProperties().getLogicDeleterField(), prefix + getMybatisPlusProperties().getLogicDeleterProp(),
                getMybatisPlusProperties().getLogicDeleteTimeField(), prefix + getMybatisPlusProperties().getLogicDeleteTimeProp());
    }

    /**
     * EntityWrapper方式获取select where（逻辑删除）
     * @param newLine
     * @param table
     * @return
     */
    protected String mySqlWhereEntityWrapperForLogicDelete(boolean newLine, TableInfo table){
        String sqlScript = myGetAllSqlWhereUnContainLogicDeleteFiled(true, WRAPPER_ENTITY_DOT, table);//ew.entity.
        sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", WRAPPER_ENTITY), true) + NEWLINE;//<if test="ew.entity != null"></if>

        
        String normalSqlScript = SqlScriptUtils.convertIf(String.format("AND ${%s}", WRAPPER_SQLSEGMENT),//ew.sqlSegment
                String.format("%s != null and %s != '' and %s", WRAPPER_SQLSEGMENT, WRAPPER_SQLSEGMENT,
                        WRAPPER_NONEMPTYOFNORMAL), true);
        normalSqlScript += NEWLINE;
        normalSqlScript += SqlScriptUtils.convertIf(String.format(" ${%s}", WRAPPER_SQLSEGMENT),
                String.format("%s != null and %s != '' and %s", WRAPPER_SQLSEGMENT, WRAPPER_SQLSEGMENT,
                        WRAPPER_EMPTYOFNORMAL), true);
        sqlScript += normalSqlScript;

        sqlScript += (NEWLINE + myGetLogicDeleteSql(true, true, null) + NEWLINE);

        sqlScript = SqlScriptUtils.convertChoose(String.format("%s != null", WRAPPER), sqlScript,//ew != null
                myGetLogicDeleteSql(false, true, null));
        sqlScript = SqlScriptUtils.convertWhere(sqlScript) + NEWLINE;
        return newLine ? NEWLINE + sqlScript : sqlScript;
    }

    /**
     * SQL map 查询条件（逻辑删除）
     * @param table
     * @return
     */
    protected String mySqlWhereByMapForLogicDelete(TableInfo table){
        // 逻辑删除
        String sqlScript = SqlScriptUtils.convertChoose("v == null", " ${k} IS NULL ",
                " ${k} = #{v} ");
        sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("k != '%s'", MybatisPlusExtConstants.LOGIC_DEL_EXT), true);
        sqlScript = SqlScriptUtils.convertForeach(sqlScript, COLUMN_MAP, "k", "v", "AND");
        sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null and !%s.isEmpty", COLUMN_MAP, COLUMN_MAP), true);
        sqlScript += (NEWLINE + myGetLogicDeleteSql(true, true, null));
        sqlScript = SqlScriptUtils.convertWhere(sqlScript);
        return sqlScript;
    }


    private String myGetAllSqlWhereUnContainLogicDeleteFiled(boolean withId, final String prefix, TableInfo table) {
        final String newPrefix = prefix == null ? EMPTY : prefix;
        String filedSqlScript = table.getFieldList().stream()
                .filter(i -> !getMybatisPlusProperties().getLogicDeleteField().equals(i.getColumn())
                && !getMybatisPlusProperties().getLogicDeleterField().equals(i.getColumn())
                && !getMybatisPlusProperties().getLogicDeleteTimeField().equals(i.getColumn()))
                .map(i -> i.getSqlWhere(newPrefix)).filter(Objects::nonNull).collect(joining(NEWLINE));
        if (!withId || StringUtils.isBlank(table.getKeyProperty())) {
            return filedSqlScript;
        }
        String newKeyProperty = newPrefix + table.getKeyProperty();
        String keySqlScript = table.getKeyColumn() + EQUALS + SqlScriptUtils.safeParam(newKeyProperty);
        return SqlScriptUtils.convertIf(keySqlScript, String.format("%s != null", newKeyProperty), false)
                + NEWLINE + filedSqlScript;
    }

    //endregion

}
